package controller;

import gui.Grass;

import java.awt.Point;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import model.Drawable;
import model.Food;
import model.Snake;

import common.Direction;

/**
 * This is the main coordination brain of the game.  Keeps a track of the Food
 * and Snakes and tells the GUI to repaint itself. 
 */
public class GameEngine implements Runnable {
	
	private int boardSize = 400;
	private int snakeSize = 10;
	private List<Snake> snakes = new ArrayList<Snake>();
	private List<Thread> snakesThreads = new ArrayList<Thread>();
	private Grass playingArea;
	private Food food;
	Map<Direction, Integer> player1Keys, player2Keys;
	private volatile boolean playing;
	
	public GameEngine(Grass playingArea, int boardSize, int snakeSize) {
		this.playingArea = playingArea;
		this.boardSize = boardSize;
		this.snakeSize = snakeSize;
	}
	
	public void run() {
		while (playing) {
			checkSnakesMovements();
			playingArea.draw(getDrawables());
			playingArea.repaint();
			try {
				Thread.sleep(500);
			} catch (InterruptedException ie) {
				Thread.currentThread().interrupt();
			}
		}
	}

	/** Allow players to be able to register to play
	 * @param snake - the snake that will be added to the game*/
	public void addPlayerSnake(Snake snake) {
		snakes.add(snake);
	}
	
	/** Allow players to be able to register to play
	 * @param snake - the snake that will be added to the game*/
	public void removePlayerSnake(Snake snake) {
		snakes.remove(snake);
	}
	
	/** Populate the food for this level */
	public void addFood(Food food) {
		this.food = food;
	}
	
	/** Let's play Snake! */
	public void startGame() {
		playing = true;
		for (Snake snake : snakes) {
			Thread snakeThread = new Thread(snake);
			snakeThread.start();
			snakesThreads.add(snakeThread);
		}
	}
	
	/** Stop any snakes from moving */
	public void stopGame() {
		for (Snake snake : snakes) {
			snake.stop();
		}
		snakesThreads.clear();
		playing = false;
	}
	
	private List<Drawable> getDrawables() {
		List<Drawable> drawables = new ArrayList<Drawable>();
		drawables.addAll(snakes);
		drawables.add(food);
		return drawables;
	}

	/**
	 * Get the coordinates of the Snakes and check that they have moved legally or
	 * have eaten some food or something
	 */
	private void checkSnakesMovements() {
		for (Snake snake : snakes) {
			if (isMoveLegal(snake)) {
				if (hasEaten(snake)) {
					snake.eaten();
				}
			} else {
				System.out.println("Illegal move, stopping game");
				stopGame();
			}
		}
	}
	
	//check the snakes haven't just run off the end of the board
	//TODO check they haven't run into each other, although Indy 
	//would say they don't really mind
	private boolean isMoveLegal(Snake snake) {
		for (Point seg : snake.getLocations()) {
			if (seg.getX() < 0 || seg.getX() > boardSize 
					|| seg.getY() < 0 || seg.getY() > boardSize) {
				return false;
			}
		}
		return true;
	}
	
	/** Has the snake just run over some food? */
	private boolean hasEaten(Snake snake) {
		for (Point foodPos : food.getLocations()) {
			for (Point snakePos : snake.getLocations()) {
				if (foodPos.x == snakePos.x && foodPos.y == snakePos.y) {
					//remove the food from the array
					food.remove(foodPos);
					return true;
				}
			}
		}
		return false;		
	}


	
}
